<?php
// +----------------------------------------------------------------------
// | 有小象汇 自研正版源码 赋能开发者
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 http://www.uxphp.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 有小象汇并不是自由软件，未经许可不能去掉有小象汇相关版权
// +----------------------------------------------------------------------
// | Author:  有小象汇
// +----------------------------------------------------------------------
namespace app\services\car;

use app\services\BaseServices;
use think\exception\ValidateException;
use think\facade\Db;

require_once(root_path() . '/vendor/alipaysdk/aop/AopClient.php');
require_once(root_path() . '/vendor/alipaysdk/aop/request/AlipayFundAuthOrderAppFreezeRequest.php');
require_once(root_path() . '/vendor/alipaysdk/aop/request/AlipayFundAuthOrderUnfreezeRequest.php');
require_once(root_path() . '/vendor/alipaysdk/aop/AopCertClient.php');
require_once(root_path() . '/vendor/alipaysdk/aop/AopCertification.php');
require_once(root_path() . '/vendor/alipaysdk/aop/AlipayConfig.php');
require_once(root_path() . '/vendor/alipaysdk/aop/request/AlipaySystemOauthTokenRequest.php');
require_once(root_path() . '/vendor/alipaysdk/aop/request/AlipayUserInfoShareRequest.php');
require_once(root_path() . '/vendor/alipaysdk/aop/request/AlipayTradePayRequest.php');
require_once(root_path() . '/vendor/alipaysdk/aop/request/ZhimaCreditScoreGetRequest.php');
require_once(root_path() . '/vendor/alipaysdk/aop/request/AlipayTradeAppPayRequest.php');
class AlipayServices extends BaseServices
{
    protected $appid = NULL;
    protected $private_key = NULL;
    protected $alipay_public_key = NULL;
    protected $server_url = NULL;
    protected $sign_type = NULL;
    protected $charset = NULL;
    protected $domain = NULL;
    protected $services = NULL;

    public function __construct(CarOrderServices $services)
    {
        $this->services = $services;
        $this->appid = sys_config('alipay_sesame_appid'); // appid
        $this->private_key = sys_config('alipay_private_key'); // 开发者私钥
        $this->alipay_public_key = sys_config('alipay_sesame_public_key'); // 支付宝公钥
        $this->server_url = 'https://openapi.alipay.com/gateway.do'; // 正式环境
        $this->sign_type = 'RSA2'; // 加密方式
        $this->charset = 'UTF-8'; // 字符编码
        $this->domain = sys_config('alipay_notify_url'); // 回调地址

    }

    /**
     * 设置配置项
     * @return \AopClient
     */
    public function setConfig(): \AopClient
    {
        $config = new \AlipayConfig();
        $config->setAppId($this->appid);
        $config->setCharset($this->charset);
        $config->setFormat("json");
        $config->setSignType($this->sign_type);
        $config->setServerUrl($this->server_url);
        $config->setPrivateKey($this->private_key);
        $config->setAlipayPublicKey($this->alipay_public_key);
        return new \AopClient($config);
    }

    /**
     * 对象转数组
     * @param $object
     * @return mixed
     */
    public function object_to_array($object)
    {
        return json_decode(json_encode($object), true);
    }

    /**
     * 支付宝资金冻结
     * @param array $data
     * @return string
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function AlipayFundAuthOrderAppFreezeRequest(array $data)
    {
        $info = $this->dao->get($data['free_id']);
        $alipayClient = $this->setConfig();
        $alipayClient->apiVersion = '1.0';
        $object = new \stdClass();
        $object->out_order_no = $info['out_order_no']; // TODO 商户订单号
        $object->out_request_no = $info['out_order_no']; // TODO 商户本次创建芝麻免押订单操作的请求流水号，不同请求需要保证唯一性
        $object->order_title = '租车押金'; // TODO 订单标题
        $object->amount = floatval($info['deposit']); // TODO 需要冻结的金额
        $object->product_code = 'PRE_AUTH_ONLINE'; // TODO 产品码，根据开通支付产品传参；开通预授权支付产品传 PREAUTH_PAY，开通支付宝预授权产品传 PRE_AUTH_ONLINE
        if($data['type'] == 'free'){ // 芝麻免押拓展参数
            $object->deposit_product_mode = 'DEPOSIT_ONLY'; // TODO 免押受理台模式：POSTPAY 表示后付金额已知、POSTPAY_UNCERTAIN 表示后付金额未知、DEPOSIT_ONLY 表示纯免押
            $type = [
                'category' => 'TRAD_RENT_CAR', // TODO 授权业务对应的类目
                'serviceId' => sys_config('alipay_service_id') // TODO 信用服务ID
            ];
            $object->extra_param = json_encode($type);
        }
        $json = json_encode($object);
        $request = new \AlipayFundAuthOrderAppFreezeRequest();
        // $request->setNotifyUrl($this->domain . '/AlipayFundAuthOrderAppFreezeNotify');
        file_put_contents('huidiaoaddress.txt' , $this->domain);
        $request->setNotifyUrl($this->domain);//回调地址
        $request->setBizContent($json);
        $result = $alipayClient->sdkExecute($request);
        return $result;
    }

    /**
     * 支付宝资金冻结回调
     * @param array $data
     * @return bool
     */
    public function AlipayFundAuthOrderAppFreezeNotify($data)
    {
        $data = (array)json_decode($data);
        file_put_contents('notify_freeze_test.log', $data);
        $aop = new \AopClient;
        $aop->alipayrsaPublicKey = $this->alipay_public_key;
        $flag = $aop->rsaCheckV1($data, NULL, "RSA2");
        file_put_contents('11.txt', 123);
        $data['flag'] = $flag;
        file_put_contents('22.txt', 123);
        $order_sn = $data['out_order_no'];
        file_put_contents('33.txt', $order_sn);
        $freeInfo = Db::table('ux_car_free_deposit_order')->where('out_order_no',$order_sn)->find();
        // $freeInfo = $this->services->getOne(['out_order_no'=>$order_sn]);
        file_put_contents('44.txt', 222222222);
        if ($data['status'] === 'SUCCESS') {
            $update = [
                'auth_no' => $data['auth_no'],
                'alipay_freeze_notify' => json_encode($data),
                'status_alipay' => $data['status'],
                'gmt_create' => strtotime($data['gmt_create']),
                'payer_user_id' => $data['payer_user_id'],
                'operation_id' => $data['operation_id'],
                'amount' => $data['amount'],
                'credit_amount' => $data['total_freeze_amount'],
                'fund_amount' => $data['rest_amount'],
                'pre_auth_type' => 'CREDIT_AUTH',
                'status' => 1,
                'pay_type'=>'alipay',
                'pay_time' => time()
            ];

            $this->dao->update($freeInfo['id'],$update);
                file_put_contents('zhifusuccess.txt', "1111111111111111");
            BaseLogServices::addLog($freeInfo['car_order_id'],2,json_encode($data),4,0,'支付宝资金冻结回调',29);
            file_put_contents('notify_freeze_success.log', json_encode($data));
            return true;
        }
        file_put_contents('notify_freeze_fail.log', json_encode($data));
        return false;
    }

    /**
     * 支付宝资金解冻
     * @param int $free_id
     * @return string[]
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function AlipayFundAuthOrderUnfreezeRequest(int $free_id)
    {
        
        $free_info = Db::table('ux_car_free_deposit_order')->where('id',$free_id)->find();
        // $free_info = $this->dao->get($free_id);
        $alipayClient = $this->setConfig();
        $alipayClient->apiVersion = "1.0";
        $object = new \stdClass();
        $object->auth_no = $free_info['auth_no']; // TODO 支付宝资金授权订单号
        $object->out_request_no = $this->getNewOrderId('CarUnfreezeOrder', 'U'); // TODO 解冻请求流水号
        $object->amount = $free_info['amount']; // TODO 本次操作解冻的金额
        $object->remark = '租车押金退回'; // TODO 商户对本次解冻操作的附言描述
        $object->extra_param = json_encode([ // TODO 解冻扩展信息
            'unfreezeBizInfo' => [ // TODO 由芝麻消费
                'bizComplete' => true, // TODO 标识本次解冻用户已履约，true表示信用单履约完结
            ]
        ]);
        $json = json_encode($object);
        $request = new \AlipayFundAuthOrderUnfreezeRequest();
        // $request->setNotifyUrl($this->domain . '/AlipayFundAuthOrderUnfreezeNotify');
        $request->setNotifyUrl('https://zc.zlcx.vip/api'. '/AlipayFundAuthOrderUnfreezeNotify');
        $request->setBizContent($json);
        $result = $alipayClient->execute($request);
        $responseNode = str_replace(".", "_", $request->getApiMethodName()) . "_response";
        $resultCode = $result->$responseNode;
        $res = $this->object_to_array($resultCode);
        // if (!empty($res['code']) && $res['code'] === 10000) {
            $data = [
                'order_sn' => $free_info['order_sn'],
                'car_order_id' => $free_info['car_order_id'],
                'status' => 0,
                'amount' => $free_info['amount'],
                'un_order_sn' => $object->out_request_no,
                'auth_no' => $free_info['auth_no'],
                'add_time'=>time(),
            ];
            CarUnfreezeOrder::create($data);
            return ['un_order_sn'=>$object->out_request_no];
        // }else{
        //     throw new ValidateException($res['sub_msg']??'系统错误');
        // }
    }

    /**
     * 支付宝资金解冻回调
     * @param array $data
     * @return mixed|string
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function AlipayFundAuthOrderUnfreezeNotify($data)
    {
        file_put_contents('UnfreezeNotify1.log', $data);
        $data = (array)json_decode($data);
        file_put_contents('UnfreezeNotify2.log', $data);
       
        $aop = new \AopClient;
        $aop->alipayrsaPublicKey = $this->alipay_public_key;
        $flag = $aop->rsaCheckV1($data, NULL, "RSA2");
        $data['flag'] = $flag;
        $un_order_sn = $data['out_request_no'];
        $unfreeze_info = CarUnfreezeOrder::where('un_order_sn',$un_order_sn)->find();
        if ($data['status'] === 'SUCCESS') {
            return $this->services->transaction(function () use ($unfreeze_info,$data){
                    $update = [
                        'alipay_unfreeze_notify' => json_encode($data),
                        'out_order_no' => $data['out_order_no'],
                        'out_request_no' => $data['out_request_no'],
                        'status_alipay' => $data['status'],
                        'gmt_trans' => strtotime($data['gmt_create']),
                        'payer_user_id' => $data['payer_logon_id'],
                        'operation_id' => $data['operation_id'],
                        'amount' => $data['amount'],
                        'credit_amount' => $data['credit_amount'],
                        'fund_amount' => $data['fund_amount'],
                        'status' => 1,
                    ];
                if(!CarUnfreezeOrder::update($update,['id'=>$unfreeze_info['id']])){
                    throw new ValidateException('系统错误');
                }
                $free_update = [
                    'status' => 3,
                    'unfreeze_id' => $unfreeze_info['id']
                ];
                if(!$this->dao->update($unfreeze_info['free_order_id'],$free_update)){
                    throw new ValidateException('系统错误');
                }
                $title = '线上资金解冻回调：'.json_encode($data);
                BaseLogServices::addLog(0,2,$title,4,0,'系统',30);
                file_put_contents('notify_unfreeze_success.log', json_encode($data));
                return 'success';
            });
        }
        file_put_contents('notify_unfreeze_fail.log', json_encode($data));
        return 'fail';
    }

    /**
     * 支付宝预授权转支付
     * @param int $free_id
     * @return mixed
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function AlipayTradePayRequest(int $free_id)
    {
        $free_info = $this->dao->get($free_id);
        $alipayClient = $this->setConfig();
        $alipayClient->apiVersion = "1.0";
        $object = new \stdClass();
        $object->out_trade_no = $this->getNewOrderId('CarTradePayOrder','T'); // TODO 商户订单号
        $object->total_amount = 0.01; // TODO 订单总金额
        $object->subject = '支付租车费用'; // TODO 订单标题
        $object->product_code = 'PRE_AUTH_ONLINE'; // TODO 产品码：FACE_TO_FACE_PAYMENT 当面付产品、CYCLE_PAY_AUTH 周期扣款产品、GENERAL_WITHHOLDING 代扣产品、PRE_AUTH_ONLINE 支付宝预授权产品、PRE_AUTH 新当面资金授权产品
        $object->auth_no = $free_info['auth_no']; // TODO 设置资金预授权单号
        $object->auth_confirm_mode = 'NOT_COMPLETE'; // TODO 预授权确认模式：COMPLETE 转交易完成后解冻剩余冻结金额、NOT_COMPLETE 转交易完成后不解冻剩余冻结金额
        $json = json_encode($object);
        $request = new \AlipayTradePayRequest();
        $request->setNotifyUrl($this->domain . '/AlipayTradePayRequestNotify');
        $request->setBizContent($json);
        $result = $alipayClient->execute($request);
        $responseNode = str_replace(".", "_", $request->getApiMethodName()) . "_response";
        $resultCode = $result->$responseNode;
        $res = $this->object_to_array($resultCode);
        if (!empty($res['code']) && $res['code'] === 10000) { // 转支付请求发起成功
            return ['out_trade_no'=>$object->out_trade_no];
        }else{
            throw new ValidateException($res['sub_msg']??'系统错误');
        }
    }

    /**
     * 预授权转支付回调
     * @param $data
     * @return mixed|string
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function AlipayTradePayRequestNotify($data)
    {
        $aop = new \AopClient;
        $aop->alipayrsaPublicKey = $this->alipay_public_key;
        $flag = $aop->rsaCheckV1($data, NULL, "RSA2");
        $data['flag'] = $flag;
        $out_trade_no = $data['out_trade_no'];
        $trade_info = CarTradePayOrder::where('out_trade_no',$out_trade_no)->find();
        if ($data['trade_status'] === 'TRADE_SUCCESS') {
            return $this->services->transaction(function () use ($trade_info,$data){
                $update = [
                    'status' => 1,
                    'trade_no' => $data['trade_no'],
                    'alipay_tradepay_notify' => json_encode($data),
                    'total_amount' => $data['total_amount'],
                    'receipt_amount' => $data['receipt_amount'],
                    'buyer_pay_amount' => $data['buyer_pay_amount'],
                    'invoice_amount' => $data['invoice_amount'],
                    'gmt_payment' => $data['gmt_payment'],
                    'buyer_user_id' => $data['buyer_user_id'],
                    'auth_trade_pay_mode' => $data['auth_trade_pay_mode'],
                ];
                if(!CarTradePayOrder::update($update,['id'=>$trade_info['id']])){
                    throw new ValidateException('系统错误');
                }
                $order_update = [
                    'status' => 5,
                    'tradepay_id' => $trade_info['id']
                ];
                if(!$this->services->update($trade_info['car_order_id'],$order_update)){
                    throw new ValidateException('系统错误');
                }
                $title = '预授权转支付回调：'.json_encode($data);
                BaseLogServices::addLog($trade_info['car_order_id'],2,$title,4,0,'预授权转支付回调',31);
                file_put_contents('notify_tradepay_success.log', json_encode($data));
                return true;
            });
        }
        file_put_contents('notify_tradepay_fail.log', json_encode($data));
        return false;
    }

    /**
     * 生成订单唯一id
     * @param string $model
     * @param string $pre
     * @return string
     * @throws \Exception
     */
    public function getNewOrderId(string $model = 'CarFreeDepositOrder', string $pre = ''): string
    {
        [$msec, $sec] = explode(' ', microtime());
        $msectime = number_format(((float)$msec + (float)$sec) * 1000, 0, '', '');
        $orderId = $pre . $msectime . random_int(10000, 99999);
        return $orderId;
    }


    /*
     * 支付宝app支付接口2.0
     *
     * */
    public function Alipay($data){
        // 初始化SDK
        $alipayClient = $this->setConfig();

        // 构造请求参数以调用接口
        $request = new \AlipayTradeAppPayRequest();
        $model = array();
        // 设置业务扩展参数
        $extendParams = array();
        $extendParams['royalty_freeze'] = "true";
        $model['extend_params'] = $extendParams;
        // 设置商户订单号
        $model['out_trade_no'] = $data['orderon'];
        // 设置订单总金额
        $model['total_amount'] = $data['amount'];
        // 设置订单标题
        $model['subject'] = $data['body'];
        // 设置产品码
//        $model['product_code'] = "QUICK_MSECURITY_PAY";
        // 设置公用回传参数
//        $model['passback_params'] = "merchantBizType%3d3C%26merchantBizNo%3d2016010101111";
        // 设置订单包含的商品列表信息
        $goodsDetail = array();
        $goodsDetail0 = array();
        $goodsDetail0['goods_name'] = $data['body'];//商品名称
//        $goodsDetail0['alipay_goods_id'] = "20010001";
        $goodsDetail0['quantity'] = $data['quantity'];//商品数量
        $goodsDetail0['price'] = $data['price'];//商品单价，单位为元
//        $goodsDetail0['goods_id'] = "apple-01";
//        $goodsDetail0['goods_category'] = "34543238";
//        $goodsDetail0['categories_tree'] = "124868003|126232002|126252004";
//        $goodsDetail0['show_url'] = "http://www.alipay.com/xxx.jpg";
        $goodsDetail[] = $goodsDetail0;
        $model['goods_detail'] = $goodsDetail;
        // 设置商户的原始订单号
//        $model['merchant_order_no'] = "20161008001";
        $request->setBizContent(json_encode($model,JSON_UNESCAPED_UNICODE));
        // 如果是第三方代调用模式，请设置app_auth_token（应用授权令牌）
        $orderStr = $alipayClient->sdkExecute($request);
        return $orderStr;

    }


}